/* CsJni - .NET / Java Bridge
 * 
 * Copyright 2010 Robert E. Burke Licensed under the Apache License, Version 
 * 2.0 (the "License"); you may not use this file except in compliance with 
 * the License. You may obtain a copy of the License at 
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable 
 * law or agreed to in writing, software distributed under the License is 
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 * KIND, either express or implied. See the License for the specific language 
 * governing permissions and limitations under the License. 
*/

using System;
using System.Collections.Generic;
using System.Text;

namespace CsJni
{
    public abstract class JniMember
    {
        private IntPtr mHandle;
        private JniClass mDeclaringClass;
        private bool mIsStatic;
        private JniType mJniType;
        private int mArrayRank;

        protected JniMember(IntPtr handle, JniClass declaringClass, bool isStatic, string signature)
        {
            if (handle == IntPtr.Zero)
            {
                throw new JniException("TODO");
            }
            VerifyInputJniObject(declaringClass);
            mHandle = handle;
            mDeclaringClass = declaringClass;
            mIsStatic = isStatic;

            // TODO - refactor this mess
            string returnType = signature.Trim();
            int pos = returnType.LastIndexOf(')');
            if (pos > -1)
                returnType = returnType.Substring(pos + 1);
            pos = returnType.LastIndexOf('[');
            mArrayRank = -1;
            string type = returnType;
            if (pos > -1)
            {
                mArrayRank = pos + 1;
                type = type.Substring(pos + 1);
            }
            if (type.Length == 1)
            {
                if (type == "V")
                {
                    mJniType = JniType.Void;
                }
                else
                {
                    mJniType = CsJni.JniArray.ParseArrayPrimitiveType(type);
                    if (mJniType == JniType.Null)
                    {
                        throw new JniException("TODO");
                    }
                }
            }
            else
            {
                if (!(type.StartsWith("L", StringComparison.Ordinal) && type.EndsWith(";", StringComparison.Ordinal)))
                {
                    throw new JniException("TODO");
                }
                switch (type)
                {
                    case "Ljava/lang/String;": mJniType = JniType.String; break;
                    case "Ljava/lang/Class;": mJniType = JniType.Class; break;
                    case "Ljava/lang/Throwable;": mJniType = JniType.Throwable; break;
                    default: mJniType = JniType.NonPrimitive; break;
                }
            }
        }

        public bool IsStatic
        {
            get { return mIsStatic; }
        }

        public IntPtr Handle
        {
            get { return mHandle; }
        }

        public JniClass DeclaringClass
        {
            get { return mDeclaringClass; }
        }

        public JniType ReturnJniType
        {
            get { return mJniType; }
        }

        public int ReturnArrayRank
        {
            get { return mArrayRank; }
        }

        internal static void VerifyEnvironment(JniEnvironment environment)
        {
            VerifyInputObject(environment);
        }

        internal static void VerifyInputObject(object input)
        {
            if (input == null)
            {
                throw new JniException(JniResourceManager.Instance.GetString("invalidObject"));
            }
        }

        internal static void VerifyInputJniObject(JniObject jniObject)
        {
            if (!(jniObject != null && (jniObject.Handle != IntPtr.Zero)))
            {
                throw new JniException("TODO");
            }
        }

        protected void VerifyStatic()
        {
            if (!mIsStatic)
            {
                throw new JniException("TODO");
            }
        }

        protected void VerifyNotStatic()
        {
            if (mIsStatic)
            {
                throw new JniException("TODO");
            }
        }

        protected void VerifyReturnType(JniType type)
        {
            if (this.ReturnJniType != type)
            {
                throw new JniException("TODO");
            }
        }

        protected void VerifyObjectReturnType()
        {
            switch (this.ReturnJniType)
            {
                case JniType.Boolean: goto case JniType.Short;
                case JniType.Byte: goto case JniType.Short;
                case JniType.Char: goto case JniType.Short;
                case JniType.Double: goto case JniType.Short;
                case JniType.Float: goto case JniType.Short;
                case JniType.Int: goto case JniType.Short;
                case JniType.Long: goto case JniType.Short;
                case JniType.Short: if (this.ReturnArrayRank < 1) { throw new JniException("TODO"); } return;
                case JniType.String: return;
                case JniType.Throwable: return;
                case JniType.Class: return;
                case JniType.NonPrimitive: return;
                default: throw new JniException("TODO");
            }
        }
    }
}
